/*            Copyright(c) 2006-2008 Dave Sexton           *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Configuration.Provider;
using DaveSexton.DocProject.Engine;
using VSLangProj80;
using System.Configuration;
using System.ComponentModel;
using System.Collections.Generic;
using DaveSexton.DocProject.Wizards.Foundation;
using System.IO.IsolatedStorage;

namespace DaveSexton.DocProject.Configuration
{
	[TypeConverter(typeof(SortedPropertyConverter))]
	public abstract class BuildEngineProvider : ProviderBase
	{
		#region Public Properties
		[Browsable(false)]
		public override string Description
		{
			get
			{
				return base.Description;
			}
		}

		[Browsable(false)]
		public override string Name
		{
			get
			{
				return base.Name;
			}
		}

		public string this[string setting]
		{
			get
			{
        return Settings[setting];
			}
			set
			{
        Settings[setting] = value;
			}
		}

		[Browsable(false)]
		public virtual bool HasToolBars
		{
			get
			{
				return false;
			}
		}

		[Browsable(false)]
		public IEnumerable<ToolBar> ToolBars
		{
			get
			{
				return new MarshalByRefEnumerable<ToolBar>(ToolBarsInternal);
			}
		}

		[Browsable(false)]
		public virtual bool HasToolWindows
		{
			get
			{
				return false;
			}
		}

		[Browsable(false)]
		public IEnumerable<ToolWindow> ToolWindows
		{
			get
			{
				return new MarshalByRefEnumerable<ToolWindow>(ToolWindowsInternal);
			}
		}

		[Browsable(false)]
		public ProviderSettingsDictionary Settings
		{
			get
			{
				if (settings == null)
					settings = new IsolatedProviderSettings(DocProjectEnvironment.FindProviderSettings(this),
						IsolatedStorageFile.GetUserStoreForAssembly(), GetType());

				return settings;
			}
		}
		#endregion

		#region Private / Protected
		protected virtual IEnumerable<ToolBar> ToolBarsInternal
		{
			get
			{
				yield break;
			}
		}

		protected virtual IEnumerable<ToolWindow> ToolWindowsInternal
		{
			get
			{
				yield break;
			}
		}

		protected internal virtual string CustomExternalSourcesAssemblyOrFileDialogFilter
		{
			get
			{
				return null;
			}
		}

		protected internal virtual bool UseExternalSourcesAssemblyDialogFilter
		{
			get
			{
				return true;
			}
		}

		protected internal ICollection<string> AllSupportedExternalSourceFileExtensions
		{
			get
			{
				List<string> extensions = new List<string>(8);

				string customFilter = CustomExternalSourcesAssemblyOrFileDialogFilter;

				if (UseExternalSourcesAssemblyDialogFilter)
				{
					if (string.IsNullOrEmpty(customFilter))
					{
						extensions.Add(".dll");
						extensions.Add(".exe");
					}
					else
						foreach (string extension in PathFormat.GetUniqueDialogFilterExtensions(
							StringComparison.OrdinalIgnoreCase, customFilter, true, ".dll", ".exe"))
							extensions.Add(extension);
				}
				else
				{
					if (!string.IsNullOrEmpty(customFilter))
						foreach (string extension in PathFormat.GetUniqueDialogFilterExtensions(
							StringComparison.OrdinalIgnoreCase, customFilter))
							extensions.Add(extension);
				}

				if (extensions.Count == 0)
					throw new InvalidOperationException(Resources.Errors.NoSupportedSourceFileTypes);

				return extensions.AsReadOnly();
			}
		}

		private IsolatedProviderSettings settings;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="BuildEngineProvider" /> class for derived classes.
		/// </summary>
		protected BuildEngineProvider()
		{
		}
		#endregion

		#region Methods
		public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
		{
			if (config == null)
				throw new ArgumentNullException("config");

			if (string.IsNullOrEmpty(config["description"]))
			{
				config.Remove("description");
				config.Add("description", this.GetType().Name);
			}

			base.Initialize(name, config);
		}

		public abstract void Load();

		public abstract void Unload();

		public abstract bool CreatesBuildEngineOfType(Type type);

		public abstract IBuildEngine CreateBuildEngine(IDocProject project);

		public abstract DocProjectOptions CreateProjectOptions(IDocProject project);

		public abstract BuildSettings CreateBuildSettings(IBuildEngine engine);

		public abstract WizardStep CreateNewProjectWizardStep(IDocProject project);

		public virtual void NotifyNewProjectWizardCompleted(IDocProject project, WizardController controller, bool succeeded)
		{
			// for derived classes
		}

		/// <summary>
		/// This method is called by the <strong>New Project Wizard</strong> to ensure that the user may 
		/// choose the provider.  Derived classes should override this method and throw an exception if 
		/// the provider is not valid for the current installation.
		/// </summary>
		public virtual void Verify()
		{
		}

		/// <summary>
		/// Allows derived build engine providers to participate in the uninstallation of DocProject.
		/// </summary>
		protected internal virtual void Uninstall()
		{
			// do nothing
		}

		public virtual void CommitProviderSettings()
    {
      if (settings != null && settings.CanCommit)
        settings.Commit();
    }

		public virtual void CancelProviderSettings()
    {
      if (settings != null)
        settings.Clear();
    }
		#endregion

		#region Nested
		private sealed class IsolatedProviderSettings : ProviderSettingsDictionary
		{
			#region Public Properties
			#endregion

			#region Private / Protected
			private readonly IsolatedSettingsDictionary<string, string> userSettings;
			#endregion

			#region Constructors
			/// <summary>
			/// Constructs a new instance of the <see cref="IsolatedProviderSettings" /> class.
			/// </summary>
			public IsolatedProviderSettings(ProviderSettings settings, IsolatedStorageFile storage, Type type)
				: base(settings, System.Globalization.CultureInfo.InvariantCulture, StringComparer.OrdinalIgnoreCase)
			{
				userSettings = new IsolatedSettingsDictionary<string, string>(storage, type, 
					System.Globalization.CultureInfo.InvariantCulture, StringComparer.OrdinalIgnoreCase);
			}
			#endregion

			#region Methods
			public override string GetCommittedValue(string name)
			{
				return (userSettings.IsCommitted(name))
					? userSettings.GetCommittedValue(name)
					: base.GetCommittedValue(name);
			}

			public override bool IsCommitted(string name)
			{
				return userSettings.IsCommitted(name) || base.IsCommitted(name);
			}

			public override bool IsDirty(string name)
			{
				return userSettings.IsDirty(name, StringComparer.OrdinalIgnoreCase) || base.IsDirty(name);
			}

			public override void SetCommittedValue(string name, string value)
			{
				// all values must be commited to isolated storage instead of the provider setting's configuration file
				userSettings.SetCommittedValue(name, value);
			}

			public override void Commit()
			{
				userSettings.Clear();

				base.Commit();

				userSettings.Save();
			}

			public override void Delete(string name)
			{
				userSettings.Delete(name);
			}
			#endregion
		}
		#endregion
	}
}
